<?php

declare(strict_types=1);

namespace app\eslib;

/**
 * 字符串 助手类
 * 兼容: think/helper/Str
 * 借鉴: https://lodash.com/
 * @version 1.0.1
 */
class EsString
{
    // ========== think/helper/Str ===================


    protected static $snakeCache = [];

    protected static $camelCache = [];

    protected static $studlyCache = [];

    /**
     * 检查字符串中是否包含某些字符串
     * @param string       $haystack
     * @param string|array $needles
     * @return bool
     */
    public static function contains(string $haystack, $needles): bool
    {
        foreach ((array) $needles as $needle) {
            if ('' != $needle && mb_strpos($haystack, $needle) !== false) {
                return true;
            }
        }

        return false;
    }

    /**
     * 检查字符串是否以某些字符串结尾
     *
     * @param  string       $haystack
     * @param  string|array $needles
     * @return bool
     */
    public static function endsWith(string $haystack, $needles): bool
    {
        foreach ((array) $needles as $needle) {
            if ((string) $needle === static::substr($haystack, -static::length($needle))) {
                return true;
            }
        }

        return false;
    }

    /**
     * 检查字符串是否以某些字符串开头
     *
     * @param  string       $haystack
     * @param  string|array $needles
     * @return bool
     */
    public static function startsWith(string $haystack, $needles): bool
    {
        foreach ((array) $needles as $needle) {
            if ('' != $needle && mb_strpos($haystack, $needle) === 0) {
                return true;
            }
        }

        return false;
    }

    /**
     * 获取指定长度的随机字母数字组合的字符串
     *
     * @param  int $length
     * @param  int $type
     * @param  string $addChars
     * @return string
     */
    public static function random(int $length = 6, int $type = null, string $addChars = ''): string
    {
        $str = '';
        switch ($type) {
            case 0:
                $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' . $addChars;
                break;
            case 1:
                $chars = str_repeat('0123456789', 3);
                break;
            case 2:
                $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' . $addChars;
                break;
            case 3:
                $chars = 'abcdefghijklmnopqrstuvwxyz' . $addChars;
                break;
            case 4:
                $chars = "们以我到他会作时要动国产的一是工就年阶义发成部民可出能方进在了不和有大这主中人上为来分生对于学下级地个用同行面说种过命度革而多子后自社加小机也经力线本电高量长党得实家定深法表着水理化争现所二起政三好十战无农使性前等反体合斗路图把结第里正新开论之物从当两些还天资事队批点育重其思与间内去因件日利相由压员气业代全组数果期导平各基或月毛然如应形想制心样干都向变关问比展那它最及外没看治提五解系林者米群头意只明四道马认次文通但条较克又公孔领军流入接席位情运器并飞原油放立题质指建区验活众很教决特此常石强极土少已根共直团统式转别造切九你取西持总料连任志观调七么山程百报更见必真保热委手改管处己将修支识病象几先老光专什六型具示复安带每东增则完风回南广劳轮科北打积车计给节做务被整联步类集号列温装即毫知轴研单色坚据速防史拉世设达尔场织历花受求传口断况采精金界品判参层止边清至万确究书" . $addChars;
                break;
            default:
                $chars = 'ABCDEFGHIJKMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz23456789' . $addChars;
                break;
        }
        if ($length > 10) {
            $chars = $type == 1 ? str_repeat($chars, $length) : str_repeat($chars, 5);
        }
        if ($type != 4) {
            $chars = str_shuffle($chars);
            $str = substr($chars, 0, $length);
        } else {
            for ($i = 0; $i < $length; $i++) {
                $str .= mb_substr($chars, floor(mt_rand(0, mb_strlen($chars, 'utf-8') - 1)), 1);
            }
        }
        return $str;
    }

    /**
     * 字符串转小写
     *
     * @param  string $value
     * @return string
     */
    public static function lower(string $value): string
    {
        return mb_strtolower($value, 'UTF-8');
    }

    /**
     * 字符串转大写
     *
     * @param  string $value
     * @return string
     */
    public static function upper(string $value): string
    {
        return mb_strtoupper($value, 'UTF-8');
    }

    /**
     * 获取字符串的长度
     *
     * @param  string $value
     * @return int
     */
    public static function length(string $value): int
    {
        return mb_strlen($value);
    }

    /**
     * 截取字符串
     *
     * @param  string   $string
     * @param  int      $start
     * @param  int|null $length
     * @return string
     */
    public static function substr_xxx(string $string, int $start, int $length = null): string
    {
        return mb_substr($string, $start, $length, 'UTF-8');
    }

    /**
     * 驼峰转下划线
     *
     * @param  string $value
     * @param  string $delimiter
     * @return string
     */
    public static function snake(string $value, string $delimiter = '_'): string
    {
        $key = $value;

        if (isset(static::$snakeCache[$key][$delimiter])) {
            return static::$snakeCache[$key][$delimiter];
        }

        if (!ctype_lower($value)) {
            $value = preg_replace('/\s+/u', '', ucwords($value));

            $value = static::lower(preg_replace('/(.)(?=[A-Z])/u', '$1' . $delimiter, $value));
        }

        return static::$snakeCache[$key][$delimiter] = $value;
    }

    /**
     * 下划线转驼峰(首字母小写)
     *
     * @param  string $value
     * @return string
     */
    public static function camel(string $value): string
    {
        if (isset(static::$camelCache[$value])) {
            return static::$camelCache[$value];
        }

        return static::$camelCache[$value] = lcfirst(static::studly($value));
    }

    /**
     * 下划线转驼峰(首字母大写)
     *
     * @param  string $value
     * @return string
     */
    public static function studly(string $value): string
    {
        $key = $value;

        if (isset(static::$studlyCache[$key])) {
            return static::$studlyCache[$key];
        }

        $value = ucwords(str_replace(['-', '_'], ' ', $value));

        return static::$studlyCache[$key] = str_replace(' ', '', $value);
    }

    /**
     * 转为首字母大写的标题格式
     *
     * @param  string $value
     * @return string
     */
    public static function title(string $value): string
    {
        return mb_convert_case($value, MB_CASE_TITLE, 'UTF-8');
    }

    // ======================= loash.js ===============================
    /**
     * 提取数字
     */
    public static function parseNumber($text, $default = 0)
    {
        return preg_match('/\d+/', $text, $match) ? $match[0] : $default;
    }
    /**
     * 获取全球唯一标识
     * @return string
     */
    public static function uuid()
    {
        return sprintf(
            '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
            mt_rand(0, 0xffff),
            mt_rand(0, 0xffff),
            mt_rand(0, 0xffff),
            mt_rand(0, 0x0fff) | 0x4000,
            mt_rand(0, 0x3fff) | 0x8000,
            mt_rand(0, 0xffff),
            mt_rand(0, 0xffff),
            mt_rand(0, 0xffff)
        );
    }

    /**
     * unicode转汉字
     */
    public static function unicodeDecode($unicode_str)
    {
        $jsonText = '{"text":"' . $unicode_str . '"}';
        $data = json_decode($jsonText, true);
        return $data ? $data['text'] : '';
    }

    /**
     * 纯数字
     */
    public static function newNum($length = 4)
    {
        $str = '0123456789'; // 10个字符
        $strlen = 10;
        while ($length > $strlen) {
            $str .= $str;
            $strlen += 10;
        }
        return substr(str_shuffle($str), 0, $length);
    }

    /**
     * 纯字母
     */
    public static function newAlpha($length = 8)
    {
        $str = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; // 52个字符
        $strlen = 52;
        while ($length > $strlen) {
            $str .= $str;
            $strlen += 52;
        }
        return substr(str_shuffle($str), 0, $length);
    }
    /**
     * 字母和数字
     */
    public static function newAlphaNum($length = 8)
    {
        $str = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; // 62个字符
        $strlen = 62;
        while ($length > $strlen) {
            $str .= $str;
            $strlen += 62;
        }
        return substr(str_shuffle($str), 0, $length);
    }
    /**
     * 字母、数字，以及破折号 (-) 和下划线 ( _ )
     */
    public static function newAlphaDash($length = 8)
    {
        $str = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-'; // 64个字符
        $strlen = 64;
        while ($length > $strlen) {
            $str .= $str;
            $strlen += 64;
        }
        return substr(str_shuffle($str), 0, $length);
    }
    /**
     * 汉字
     */
    public static function newChs($length = 1)
    {
        $text = '';
        for ($i = 0; $i < $length; $i++) {
            // Unicode 10 进制
            $i10 = rand(19968, 40869);
            // Unicode 16 进制
            $i16 = dechex($i10);
            $text .= self::unicodeDecode('\\u' . $i16);
        }
        return $text;
    }
    /**
     * Email
     */
    public static function newEmail()
    {
    }
    /**
     * URL
     */
    public static function newUrl()
    {
        # code...
    }
    /**
     * IP
     */
    public static function newIp($type = 'ip4')
    {
        # code...
    }
    /**
     * 手机号
     */
    public static function newMobile()
    {
        # code...
    }
    /**
     * 身份证格式
     */
    public static function newIdCard()
    {
        # code...
    }
    /**
     * 类名转换为数据表名
     * @param string $name 类名称
     */
    public static function classname2table($name)
    {
        if (!$name) {
            return $name;
        }
        $chars = str_split($name);
        array_walk($chars, function (&$v, $i) {
            $ord = ord($v);
            if ($ord <= 90 && $ord >= 65) {
                $v = strtolower($v);
                if ($i > 0) {
                    $v = '_' . $v;
                }
            }
        });
        return implode('', $chars);
    }

    /**
     * 数据表名转换为类名
     * @param string $table 数据表名称
     */
    public static function table2classname($table)
    {
        return str_replace(' ', '', ucwords(str_replace('_', ' ', $table)));
    }

    /**
     * 剪短文字
     */
    public static function shortText($text, $length = 32, $suffix = '...')
    {
        if (empty($text) || (strlen($text) <= $length)) {
            return $text;
        }
        return substr($text, 0, $length) . $suffix;
    }

    /**
     * 剪短MD5
     */
    public static function shortMD5($text)
    {
        return substr(md5(strval($text)), 8, 16);
    }

    /**
     * HTML 内容转换为纯文本
     * 例如：html2text($content,['/[\*|？|！|。|，]+/']);
     * @param string
     * @return
     */
    public static function html2text($content, $expattern = [])
    {
        // 将 html 实体符号（&nbsp; 等）还原成 html 标签 -> 过滤首尾空白字符 -> 过滤 html 标签
        $content = strip_tags(trim(html_entity_decode($content)));
        $pattern = [
            '/\s/', // 匹配任何空白字符，包括空格、制表符、换页符等，等价于 [\f\n\r\t\v]
        ];
        if ($expattern) {
            $pattern = array_merge($pattern, $expattern);
        }
        return preg_replace($pattern, '', $content);
    }
    /**
     * 多字节过滤
     */
    public static function mb_trim($string, $charlist = '\\\\s', $ltrim = true, $rtrim = true)
    {
        $both_ends = $ltrim && $rtrim;

        $char_class_inner = preg_replace(
            array('/[\^\-\]\\\]/S', '/\\\{4}/S'),
            array('\\\\\\0', '\\'),
            $charlist
        );

        $work_horse = '[' . $char_class_inner . ']+';
        $ltrim && $left_pattern = '^' . $work_horse;
        $rtrim && $right_pattern = $work_horse . '$';

        if ($both_ends) {
            $pattern_middle = $left_pattern . '|' . $right_pattern;
        } elseif ($ltrim) {
            $pattern_middle = $left_pattern;
        } else {
            $pattern_middle = $right_pattern;
        }

        return preg_replace("/$pattern_middle/usSD", '', $string);
    }


    /**
     * 字符串截取
     *
     * @param string $str     需要截取的字符串
     * @param int    $start   开始位置
     * @param int    $length  截取长度
     * @param bool   $suffix  截断显示字符
     * @param string $charset 编码格式
     * @return string 
     */
    public static function substr($str, $start = 0, $length = 10, $suffix = '...', $charset = "utf-8")
    {
        if (function_exists("mb_substr")) {
            $slice = mb_substr($str, $start, $length, $charset);
        } elseif (function_exists('iconv_substr')) {
            $slice = iconv_substr($str, $start, $length, $charset);
        } else {
            $re['utf-8']  = "/[\x01-\x7f]|[\xc2-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xff][\x80-\xbf]{3}/";
            $re['gb2312'] = "/[\x01-\x7f]|[\xb0-\xf7][\xa0-\xfe]/";
            $re['gbk']    = "/[\x01-\x7f]|[\x81-\xfe][\x40-\xfe]/";
            $re['big5']   = "/[\x01-\x7f]|[\x81-\xfe]([\x40-\x7e]|\xa1-\xfe])/";
            preg_match_all($re[$charset], $str, $match);
            $slice = join("", array_slice($match[0], $start, $length));
        }
        return mb_strlen($str) >= $length ? ($slice . $suffix) : $slice;
    }
    /**
     * chunk_split() 函数中文版
     */
    public static function mb_chunk_split($str, $len = 16, $separator = "\n")
    {
        if (mb_strlen($str) <= $len) {
            return $str;
        }
        return implode($separator, mb_str_split($str, $len));
    }

    /**
     * str_split() 函数中文版
     */
    public static function mb_str_split($str, $split_length = 1, $charset = "UTF-8")
    {
        if (func_num_args() == 1) {
            return preg_split('/(?<!^)(?!$)/u', $str);
        }
        if ($split_length < 1) return false;
        $len = mb_strlen($str, $charset);
        $arr = array();
        for ($i = 0; $i < $len; $i += $split_length) {
            $s = mb_substr($str, $i, $split_length, $charset);
            $arr[] = $s;
        }
        return $arr;
    }
}
